﻿using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Runtime.InteropServices;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 组件实例的引用路径
    /// </summary>
    /// <remarks>对 SketchUpAPI 中的 SUInstanceRef 的包装</remarks>
    public class InstancePath : ObjectBase
    {
        #region API 函数
        /// <summary>
        /// 创建一个引用路径
        /// </summary>
        /// <param name="instance_path"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathCreate(out IntPtr instance_path);

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="instance_path"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathRelease(ref IntPtr instance_path);

        /// <summary>
        /// 复制一份路径
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="source_path"><see cref="InstancePath"/>另一个路径</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathCreateCopy(out IntPtr instance_path, IntPtr source_path);

        /// <summary>
        /// 向组件传入路径
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="component_instance"><see cref="ComponentInstance"/> 组件实例</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathPushInstance(IntPtr instance_path, IntPtr component_instance);

        /// <summary>
        /// 弹出最后一级路径
        /// </summary>
        /// <param name="instance_path"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathPopInstance(IntPtr instance_path);

        /// <summary>
        /// 设置一个叶路径
        /// </summary>
        /// <param name="instance_path">可以传入 0，取消指向 <paramref name="entity"/> 的路径</param>
        /// <param name="entity"><see cref="Entity"/> 物体</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathSetLeaf(IntPtr instance_path, IntPtr entity);

        /// <summary>
        /// 获取路径深度
        /// </summary>
        /// <remarks>只计算指向组件实例的路径，不计算叶节点 </remarks>
        /// <param name="instance_path"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetPathDepth(IntPtr instance_path, out long depth);

        /// <summary>
        /// 获取路径深度，包括叶节点
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="full_depth"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetFullDepth(IntPtr instance_path, out long full_depth);

        /// <summary>
        /// 获取变换
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetTransform(IntPtr instance_path, ref Transformation transform);

        /// <summary>
        /// 获取某一级深度实例的变换
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="depth"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetTransformAtDepth(IntPtr instance_path, long depth, ref Transformation transform);

        /// <summary>
        /// 获取某一级深度的实例
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="depth"></param>
        /// <param name="instance"><see cref="ComponentInstance"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetInstanceAtDepth(IntPtr instance_path, long depth, ref IntPtr instance);

        /// <summary>
        /// 获取叶节点实例
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="entity"><see cref="Entity"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetLeafAsEntity(IntPtr instance_path, out IntPtr entity);

        /// <summary>
        /// 以 <see cref="DrawingElement"/> 的形式获取叶节点
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="drawing_element"><see cref="DrawingElement"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetLeaf(IntPtr instance_path, out IntPtr drawing_element);

        /// <summary>
        /// 判断该路径实例是否有效
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="valid"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathIsValid(IntPtr instance_path, out bool valid);

        /// <summary>
        /// 判断该路径实例是否为空
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="empty"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathIsEmpty(IntPtr instance_path, out bool empty);

        /// <summary>
        /// 判断该路径实例是否包含某个物体
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="entity"><see cref="Entity"/></param>
        /// <param name="contains"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathContains(IntPtr instance_path, IntPtr entity, out bool contains);

        /// <summary>
        /// 获取该路径的PID
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="pid"><see cref="StringRef"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetPersistentID(IntPtr instance_path, ref IntPtr pid);

        /// <summary>
        /// 获取某一级深度的PID
        /// </summary>
        /// <param name="instance_path"></param>
        /// <param name="depth"></param>
        /// <param name="pid"><see cref="StringRef"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUInstancePathGetPersistentIDAtDepth(IntPtr instance_path, long depth, ref IntPtr pid);
        #endregion

        /// <summary>
        /// 是否有效
        /// </summary>
        public bool IsValid
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathIsValid(Id, out bool valid));
                return valid;
            }
        }

        /// <summary>
        /// 是否为空
        /// </summary>
        public bool IsEmpth
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathIsEmpty(Id, out bool empty));
                return empty;
            }
        }

        /// <summary>
        /// 路径ID
        /// </summary>
        public string PersistentID
        {
            get
            {
                StringRef s = StringRef.Empty;
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetPersistentID(Id, ref s.Id));
                return s.Dispose();
            }
        }

        /// <summary>
        /// 主路径深度
        /// </summary>
        public int Depth
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetPathDepth(Id, out long d));
                return (int)d;
            }
        }

        /// <summary>
        /// 总深度，包括叶节点
        /// </summary>
        public int FullDepth
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetFullDepth(Id, out long d));
                return (int)d;
            }
        }

        /// <summary>
        /// 叶节点
        /// </summary>
        public Entity Leaf
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetLeafAsEntity(Id, out IntPtr leaf));
                return new Entity(leaf);
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathSetLeaf(Id, value.Id));
            }
        }

        /// <summary>
        /// 获取变换
        /// </summary>
        public Transformation Transform
        {
            get
            {
                Transformation t = new Transformation();
                SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetTransform(Id, ref t));
                return t;
            }
        }

        /// <summary>
        /// 创建一个路径
        /// </summary>
        public InstancePath()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathCreate(out Id));
        }

        /// <summary>
        /// 从另一个路径复制
        /// </summary>
        /// <param name="another"></param>
        public InstancePath(InstancePath another)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathCreateCopy(out Id, another.Id));
        }

        internal InstancePath(IntPtr id) => Id = id;

        /// <summary>
        /// 向某个组件传入路径
        /// </summary>
        /// <param name="instance"></param>
        public void PushInstance(ComponentInstance instance)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathPushInstance(Id, instance.Id));
        }

        /// <summary>
        /// 弹出最后一级路径
        /// </summary>
        public void Pop()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathPopInstance(Id));
        }

        /// <summary>
        /// 以 <see cref="DrawingElement"/> 的形式获取叶节点
        /// </summary>
        /// <returns></returns>
        public DrawingElement GetLeafAsDrawingElement()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetLeaf(Id, out IntPtr leaf));
            return new DrawingElement(leaf);
        }

        /// <summary>
        /// 获取某一级深度物体的变换
        /// </summary>
        /// <param name="depth"></param>
        /// <returns></returns>
        public Transformation GetTransformAtDepth(int depth)
        {
            Transformation t = new Transformation();
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetTransformAtDepth(Id, depth, ref t));
            return t;
        }

        /// <summary>
        /// 获取某一级深度的组件实例
        /// </summary>
        /// <param name="depth"></param>
        /// <returns></returns>
        public ComponentInstance GetComponentInstanceAtDepth(int depth)
        {
            IntPtr i = IntPtr.Zero;
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetInstanceAtDepth(Id, depth, ref i));
            return new ComponentInstance(i);
        }

        public string GetPersistentIDAtDepth(int depth)
        {
            StringRef s = StringRef.Empty;
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathGetPersistentIDAtDepth(Id, depth, ref s.Id));
            return s.Dispose();
        }

        /// <summary>
        /// 是否包含某个物体
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Contains(Entity entity)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathContains(Id, entity.Id, out bool contains));
            return contains;
        }

        public override void Dispose()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUInstancePathRelease(ref Id));
        }
    }
}